package com.unicdata.ai.demo_2af.aspect;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.unicdata.ai.demo_2af.annotation.Log;
import com.unicdata.ai.demo_2af.common.entity.User;
import com.unicdata.ai.demo_2af.common.utils.IpUtils;
import com.unicdata.ai.demo_2af.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 日志切面
 *
 * @author lhn
 * @date 2025/06/25 17:02
 * @since 1.0.0
 **/
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 定义切点,匹配带有@Log注解的方法
     */
    @Pointcut("@annotation(com.unicdata.ai.demo_2af.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 环绕通知
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 执行方法
        Object result;
        Exception exception = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            // 执行时长(毫秒)
            long time = System.currentTimeMillis() - startTime;
            // 保存日志
            saveLog(joinPoint, time, exception);
        }
        return result;
    }

    /**
     * 保存日志
     */
    private void saveLog(ProceedingJoinPoint joinPoint, long time, Exception exception) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 获取注解信息
            Log logAnnotation = method.getAnnotation(Log.class);
            if (logAnnotation == null) {
                return;
            }
            String operation = logAnnotation.value();

            // 获取请求参数
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            Object[] args = joinPoint.getArgs();

            // 获取当前登录用户信息
            User loginUser = null;
            try {
                loginUser = (User) SecurityUtils.getSubject().getPrincipal();
            } catch (Exception e) {
                // 未登录状态
            }

            // 请求参数
            String params = "";
            if (args != null && args.length > 0) {
                try {
                    params = objectMapper.writeValueAsString(args);
                } catch (Exception e) {
                    log.error("转换参数异常", e);
                }
            }

            // 保存日志
            sysLogService.saveLog(
                    loginUser != null ? loginUser.getId() : null,
                    loginUser != null ? loginUser.getUsername() : "未登录用户",
                    operation,
                    joinPoint.getTarget().getClass().getName() + "." + method.getName(),
                    params,
                    time,
                    IpUtils.getIpAddress(),
                    exception == null ? 1 : 0,
                    exception != null ? exception.getMessage() : null
            );
        } catch (Exception e) {
            log.error("保存系统日志失败", e);
        }
    }
}